package helpdesk;

import com.mongodb.*;
import java.awt.Desktop;
import java.io.File;
import java.io.IOException;
import java.util.UUID;
import java.util.ArrayList;
import java.net.UnknownHostException;
import java.util.Date;
import java.util.List;

/**
 * This class deals with announcements, posts, and users and their status in the db
 */
public class MongoDB {
    
    // given an announcement object, it creates it in the db
    public static String createAnnouncement(Announcement a)
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("announcements");

        WriteResult result = collection.insert(a.toBasicDBOBject());

        return a.announceId;
    }
    
    // this function retrieves 10 announcements
    public static ArrayList<Announcement> getRecentAnnouncements()
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("announcements");
        ArrayList<Announcement> aList = new ArrayList();
        
        DBCursor cursor = collection.find().limit(10);
        
        // for each result
        while (cursor.hasNext())
        {
            // convert db obj to announcement and add it a list 
            DBObject temp = cursor.next();
            aList.add(Announcement.fromDBObject(temp));
        }
        
        return aList;
    }
    
    // given an id, updated title and body, it updates the old post with new info
    public static boolean editPost(String idForOldPost, String title, String body)
    {
        boolean success = false;
        
        // get the post
        DB db = getConnection();
        BasicDBObject parent = getPost(idForOldPost);
        BasicDBObject updated = parent;
        BasicDBObject query = new BasicDBObject();
        
        // add changes to the db obj
        updated.append("title", title);
        updated.append("body", body);
        query.put("postId", idForOldPost);
        try
        {
            // replaces old post with new post
            db.getCollection("posts").update(query, updated);
            success = true;
        }
        catch (Exception e)
        {
            System.out.println("Editing post failed");
        }
        
        return success;
    }
    
    // deletes a post from mongodb given it's id
    public static boolean deletePost(String postId)
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("posts");
        BasicDBObject search = new BasicDBObject();
        
        search.put("postId", postId);
        collection.remove(search);
        
        return true;
    }
    
    // returns 10 most recent posts to display for the forum
    public static ArrayList<Post> getRecentPosts(User steve)
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("posts");
        ArrayList<Post> list = new ArrayList();
        
        DBCursor cursor = collection.find().limit(10);
        
	while(cursor.hasNext()) {
            DBObject a = cursor.next();
            Post b = Post.toPost(a);
            
            if(b.responseId.equals("") || b.responseId == null) //& b.responses.isEmpty())
            {
                // if the post was for the graduate office only
                if (b.roleIndex == 0)
                {
                    // if the user is part of the graduate office
                    if (steve.role.equals("Graduate Assistant") || steve.role.equals("Graduate Coordinator"))
                    {
                        list.add(b);
                    }
                    // if the student was the author, allow them to view it
                    else if (b.author.equals(steve.username))
                    {
                        list.add(b);
                    }
                }
                // otherwise it is available to everyone
                else
                {
                    list.add(b);
                }
            }
	}
        
        return list;
    }
    
    // stores a new post given a post object
    public static String createPost(Post newPost)
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("posts");
                
        // entirely new post
        if (newPost.responseId == null || newPost.responseId.equals(""))
        {
            WriteResult a = collection.insert(newPost.toBasicDBObject());
            System.out.println(a.toString());
        }
        // response to a post
        else
        {
            // update the parent that is being responded to 
            // to keep track of all responses
            BasicDBObject parent = getPost(newPost.responseId);
            BasicDBObject updated = parent;
            BasicDBObject query = new BasicDBObject();
            
            ArrayList<String> responses = (ArrayList) parent.get("responses");
            responses.add(newPost.postId);
            updated.append("responses", responses);
            query.put("postId", newPost.responseId);
            
            collection.update(query, updated);
            
            // insert new post           
            collection.insert(newPost.toBasicDBObject());
        }
        
        return newPost.postId;
    }
    
    // returns a BasicDBObject given a postId
    public static BasicDBObject getPost(String postId)
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("posts");
        BasicDBObject search = new BasicDBObject();
        DBObject result = null;
        
        search.put("postId", postId);
        result = collection.findOne(search);
        
        return (BasicDBObject) result;
    }
    
    // maps a DBObject to a user object
    // TODO: add this to a user class
    public static User mapToUser(DBObject user)
    {
        if (user.get("role").equals("Student"))
        {       
            Student temp = new Student(user.get("username").toString(), 
                                       user.get("password").toString().toCharArray(), 
                                       user.get("role").toString());
            
            return temp;
        }
        else if (user.get("role").equals("Graduate Assistant"))
        {
            GraduateAssistant temp = new GraduateAssistant(user.get("username").toString(),
                                                           user.get("password").toString().toCharArray(),
                                                           user.get("role").toString());
            return temp;
        }
        else if (user.get("role").equals("Graduate Coordinator"))
        {
            GraduateCoordinator temp = new GraduateCoordinator(user.get("username").toString(), 
                                                               user.get("password").toString().toCharArray(),
                                                               user.get("role").toString());
            return temp;
        }
        
        return null;
   }
    
    // given a username and password, returns a user object from what is found in the 
    // database
    public static User lookUp(String username, char[] password)
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("users");
        BasicDBObject search = new BasicDBObject();
        
        int results = 0;
        
        search.put("username", username);
        search.put("password", password);
        DBCursor cursor = collection.find(search);
        BasicDBObject result = new BasicDBObject();
        
        while (cursor.hasNext()) {
            result = (BasicDBObject) cursor.next();
            results++;
        }
        
        if (results == 0) 
        {
            System.out.println("No results found.");
        }
        else
        {
            return mapToUser(result);
        }
        
        return null;
    }
    
    // given a username, password, and a type defining the role of the user
    public static boolean insertUser(String username, char[] password, int type) {
        DB db = getConnection();
        DBCollection collection = db.getCollection("users");
        BasicDBObject user = new BasicDBObject();
        String role = "";
        
        user.put("username", username);       
        user.put("password", password);
        
        if (type == 0)
        {
            role = "Student";
        }
        else if (type == 1)
        {
            role = "Graduate Assistant";
        }
        else if (type == 2)
        {
            role = "Graduate Coordinator";
        }
        
        user.put("role", role);
        collection.insert(user);    
        
        System.out.println("Created user\nName: " + username + "\nRole: " + role);
        return true;
    }
    
    // creates DB object so that any function that calls it may talk with the DB
    public static DB getConnection()
    {
        DB db = null;
        
        try 
        {
            db = new Mongo ("flame.mongohq.com", 27074).getDB("JohnEMongo");
            String password = "test";
            db.authenticate("test", password.toCharArray());
        } 
        catch (UnknownHostException e) 
        {
	   e.printStackTrace();
        } 
        catch (MongoException e) 
        {
	   e.printStackTrace();
	}        
        
        return db;
    }
    
    public static boolean changeRole(String username, String newRole)
    {
        boolean success = false;
        
        try
        {
            DB db = getConnection();
            DBCollection collection = db.getCollection("users");
            BasicDBObject query = new BasicDBObject();
            BasicDBObject find = new BasicDBObject();
            find.put("username", username);

            BasicDBObject update = (BasicDBObject) collection.findOne(find);

            update.append("role", newRole);
            collection.update(find, update);
            success = true;
        }
        catch (Exception e)
        {
            System.out.println("Failed to change user role. " + e.getMessage());
        }
        
        return success;
    }

    public static ArrayList<User> getPotentialUsers() 
    {
        DB db = getConnection();
        DBCollection collection = db.getCollection("users");
        ArrayList<User> users = new ArrayList();
        List<String> a = new ArrayList();
        a.add("Student");
        a.add("Graduate Assistant");
        
        BasicDBObject query = new BasicDBObject();
        query.put("role", new BasicDBObject("$in", a));
        
        DBCursor cursor = collection.find(query);
        DBObject temp;
        
        while (cursor.hasNext())
        {
            temp = cursor.next();
            User tempUsr = new User();
            tempUsr.setUsername(temp.get("username").toString());
            tempUsr.role = temp.get("role").toString();
            users.add(tempUsr);
        }
        
        for (int i = 0; i < users.size(); i++)
        {
            System.out.println(users.get(i).username + " " + users.get(i).role);
        }
        return users;        
    }
}